<?php

/*
 *	Framework namepsace
 */
namespace Nano
{
	/*
	 *	Controller class
	 *
	 *	@extends	\Kernel
	 */
	class Controller extends \Kernel
	{
		/*
		 *	$method	string	Default get method (default ($_GET) or friendly (Extra URL parsing))
		 */
		public $type = 'friendly';
		
		/*
		 *	$method	string	Request method
		 */
		public $method = 'get';
		
		/*
		 *	$protocol	string	Default server protocol
		 */
		public $protocol = 'http';
		
		/*
		 *	$pdelimiter	string	Protocol delimiter
		 */
		public $pdelimiter = '://';
		
		/*
		 *	$delimiter	string	URL delimiter (e.g. slash)
		 */
		public $delimiter = '/';
		
		/*
		 *	$icontroller	srting	Index controller (case-sensitive)
		 */
		public $icontroller = 'Index';
		
		/*
		 *	$imethod	string	Index method
		 */
		public $imethod = '__index';
		
		/*
		 *	$data	array	URL data
		 */
		public $data = array();
		
		/*
		 *	$host	string	Server's host
		 */
		public $host;
		
		/*
		 *	$url	string	Full active requested url
		 */
		public $url;
		
		/*
		 *	$request	string	Cutted request string
		 */
		public $request;
		
		
		/*
		 *	$cleared	string	Cleared full request string
		 */
		public $cleared;
		
		/*
		 *	$binds	array	Binded URLs
		 */
		public $binds = array();
		
		/*
		 *	Constructor
		 */
		public function __construct()
		{
			$this->method = strtolower(getenv('REQUEST_METHOD'));
			
			$this->request = getenv('REQUEST_URI');
			
			$this->host = getenv('HTTP_HOST');
			
			$this->url = $this->compile();
			
			if($this->type == 'friendly')
			{
				$this->clear();
			}
		}
		
		/*
		 *	Int controller
		 */
		public function int()
		{
			// Here we go
			$this->parse();	
		}
		
		/*
		 *	Check URL
		 *
		 *	@return	boolean
		 */
		private function check()
		{
			// Clean up request
			$this->controller = urldecode(substr($this->request, 1));
			
			// Prepare string
			$this->cleared = $this->request;
			
			// Compile url
			$this->cleared = $this->delimiter.rtrim($this->cleared, '/\\');
			
			// To protect private functions
			$this->cleared = preg_replace('/\_+/', '_', $this->cleared);
			
			// Remove more than 1 delemiters
			$this->cleared = preg_replace('/\\'.$this->delimiter.'+/', $this->delimiter, $this->cleared);
			
			// Well done!
			$this->cleared = $this->compile($this->cleared);

			if($this->url !== $this->cleared)
			{
				header('Location: '.$this->cleared);
			}
			
			return true;
		}
		
		/*
		 *	Parse request URL
		 */
		private function parse()
		{
			$this->check();
			
			// Read data form "$_GET" array
			if($this->type == 'default')
			{
				$this->data = $_GET;
				
				$controller = ucfirst(strtolower($this->data['controller']));
				
				$method = strtolower($this->data['method']);
			}
			
			// Read data from request string
			elseif($this->type == 'friendly')
			{
				$this->data = explode($this->delimiter, trim($this->request, $this->delimiter));
				
				$controller = ucfirst(strtolower($this->data[0]));
				
				$method = isset($this->data[1]) ? strtolower($this->data[1]) : null;
			}
			
			
			// wtf?
			else
			{
				throw new \Exception(__CLASS__.': Invalid data method');
			}
			
			// Check binds
			$binds = $this->binds();
			
			if($binds)
			{
				return $binds;
			}
			
			// Compile class name
			$class = '\Application\Controllers\\'.(empty($controller) ? $this->icontroller : $controller);
			
			// Run controller
			$this->run($class, $method);
			
			// Show 404
			Headers::send(404);
			
			exit();
		}
		
		/*
		 *	Add URL bind
		 *
		 *	@param	string	Regex
		 *	@param	array	Options array
		 */
		public function bind($regex, $options)
		{
			$this->binds[$regex] = $options;
		}
		
		/*
		 *	Bind URL 
		 *
		 *	@param	string	Regex
		 *	@param	mixed	Callable function
		 *
		 *	@return	boolean
		 */
		private function binds()
		{
			foreach($this->binds as $regex => $array)
			{
				if($array['method'] != $this->method)
				{
					continue;
				}
				
				$regex = '/'.str_replace('/', '\/', $regex).'/ui';
				
				if(preg_match($regex, $this->controller))
				{
					if($array['static'])
					{
						return preg_replace_callback($regex, $array['callback'], $this->controller);
					}
					else
					{
						$class = $array['callback'][0];
						
						$method = $array['callback'][1];
						
						$class = new $class();
						
						return preg_replace_callback($regex, array($class, $method), $this->controller);
					}
				}
			}
			
			return false;
		}
		
		/*
		 *	Run controller
		 *
		 *	@param	string Class name
		 *	@return	mixed
		 */
		private function run($class, $method = '__index')
		{
			if(class_exists($class))
			{
				$c = new $class();
				
				$method = isset($method) ? $method : $this->imethod;
				
				if(method_exists($class, $method))
				{
					// Clear args data
					unset($this->data[0], $this->data[1]);
					
					array_unique($this->data);
				
					// Call method
					return $c->{$method}($this->data, $this->type);
				}
			}
			
			return false;
		}
		
		/*
		 *	Compile full url
		 *
		 *	@param	string	Request string
		 *	@return	string
		 */
		private function compile($request = null)
		{
			return $this->protocol.$this->pdelimiter.$this->host.urldecode(isset($request) ? $request : $this->request);
		}
		
		/*
		 *	Clear global arrays for safty
		 */
		private function clear()
		{
			// He-he
			unset($_REQUEST, $_POST, $_GET);
		}
	}
}